import 'dart:typed_data';
import 'package:binary/binary.dart';
import 'package:inmotion_protocol/base/vehicle_data.dart';
import 'package:inmotion_protocol/common/compact.dart';
import 'package:inmotion_protocol/common/exceptions.dart';
import 'package:inmotion_protocol/common/mode.dart';
import 'package:inmotion_protocol/common/product_model.dart';
import 'package:inmotion_protocol/common/product_version.dart';
import 'package:inmotion_protocol/lorin/bean/base/real_time_info.dart';
import 'package:inmotion_protocol/lorin/bean/base/vehicle_real_time_info.dart';
import 'package:inmotion_protocol/lorin/bean/euc/euc_real_time_data.dart';
import 'package:inmotion_protocol/util/byte_util.dart';

class AllE25RealTimeData extends AllRealTimeData<E25RealTimeInfo,
    E25RealTimeState, E25RealTimeError> {
  AllE25RealTimeData(E25RealTimeInfo realTimeInfo,
      E25RealTimeState realTimeState, E25RealTimeError realTimeError)
      : super(realTimeInfo, realTimeState, realTimeError);
}

class E25VehicleSynthesizeRealTimeInfo extends VehicleSynthesizeRealTimeInfo<CommonVehicleRealTimeInfo, E25RealTimeState, E25RealTimeError> {
  E25VehicleSynthesizeRealTimeInfo(CommonVehicleRealTimeInfo commonVehicleRealTimeInfo, E25RealTimeState realTimeState, E25RealTimeError realTimeError) : super(commonVehicleRealTimeInfo, realTimeState, realTimeError);
}

/// 实时信息
class E25RealTimeInfo extends EucRealTimeInfo {
  E25RealTimeInfo(ProductModel model, VersionWrapper version)
      : super(model, version);

  Uint16 overSpeedTiltBackThreshold = Uint16.zero;
  Uint16 overSpeedWarningThreshold = Uint16.zero;
  Uint16 overOutputTiltBackThreshold = Uint16.zero;
  Uint16 overOutputWarningThreshold = Uint16.zero;
  Uint16 overBusCurrentTiltBackThreshold = Uint16.zero;
  Uint16 overBusCurrentWarningThreshold = Uint16.zero;

  @override
  void initCompact() {
    compact = _E25RealTimeInfoV2();
  }

  @override
  String toString() {
    String compactType = compact.runtimeType.toString();
    return 'E25RealTimeInfo{compact:$compactType, voltage: $voltage, current: $current, speed: $speed, mileage: $mileage, batteryLevel: $batteryLevel, '
        'remainderRange: $remainderRange, torque: $torque, batteryOutputPower: $batteryOutputPower, motorOutputPower: $motorOutputPower, '
        'outputRate: $outputRate, batteryMode: $batteryMode, batteryLevelForRide: $batteryLevelForRide, estimatedTotalMileage: $estimatedTotalMileage, '
        'mosTemp: $mosTemp, motorTemp: $motorTemp, batteryTemp: $batteryTemp, boardTemp: $boardTemp, lampTemp: $lampTemp, pitchAngle: $pitchAngle, '
        'pitchAimAngle: $pitchAimAngle, rollAngle: $rollAngle, speedingBrakingAngle: $speedingBrakingAngle, dynamicCurrentLimit: $dynamicCurrentLimit, '
        'dynamicSpeedLimit: $dynamicSpeedLimit, brightness: $brightness, lightBrightness: $lightBrightness, cpuTemp: $cpuTemp, imuTemp: $imuTemp}';
  }
}

class _E25RealTimeInfoV2 extends Compact<E25RealTimeInfo> {
  @override
  void fromBytes(E25RealTimeInfo output, Uint8ClampedList bytes, int offset) {
    if (bytes.length < offset + output.length()) {
      return;
    }
    output.voltage = ByteUtil.bytes2Int16Le(bytes, offset);
    offset += 2;
    output.current = ByteUtil.bytes2Int16Le(bytes, offset);
    offset += 2;
    // output.chargeVoltage = ByteUtil.bytes2Int16Le(bytes, offset);
    offset += 2;
    // output.chargeCurrent = ByteUtil.bytes2Int16Le(bytes, offset);
    offset += 2;
    output.speed = ByteUtil.bytes2Int16Le(bytes, offset);
    offset += 2;
    // output.acce = ByteUtil.bytes2Int16Le(bytes, offset);
    offset += 2;
    output.torque = ByteUtil.bytes2Int16Le(bytes, offset);
    offset += 2;
    output.outputRate = ByteUtil.bytes2Int16Le(bytes, offset);
    offset += 2;
    output.batteryOutputPower = ByteUtil.bytes2Int16Le(bytes, offset);
    offset += 2;
    output.motorOutputPower = ByteUtil.bytes2Int16Le(bytes, offset);
    offset += 2;
    output.pitchAngle = ByteUtil.bytes2Int16Le(bytes, offset);
    offset += 2;
    output.rollAngle = ByteUtil.bytes2Int16Le(bytes, offset);
    offset += 2;
    output.pitchAimAngle = ByteUtil.bytes2Int16Le(bytes, offset);
    offset += 2;
    // output.speedingBrakingAngle = ByteUtil.bytes2Int16Le(bytes, offset);
    offset += 2;
    output.mileage = ByteUtil.bytes2Uint16Le(bytes, offset);
    offset += 2;

    offset += 4; // 保留

    output.batteryLevel = ByteUtil.bytes2Uint16Le(bytes, offset);
    offset += 2;
    output.batteryLevelForRide = ByteUtil.bytes2Uint16Le(bytes, offset);
    offset += 2;
    output.estimatedTotalMileage = ByteUtil.bytes2Uint16Le(bytes, offset);
    output.remainderRange = Uint16(((output.batteryLevelForRide.value / 10000) *
            output.estimatedTotalMileage.value)
        .toInt());
    offset += 2;
    output.overSpeedTiltBackThreshold = ByteUtil.bytes2Uint16Le(bytes, offset);
    output.dynamicSpeedLimit = output.overSpeedTiltBackThreshold;
    offset += 2;
    output.overSpeedWarningThreshold = ByteUtil.bytes2Uint16Le(bytes, offset);
    offset += 2;
    output.overOutputTiltBackThreshold = ByteUtil.bytes2Uint16Le(bytes, offset);
    offset += 2;
    output.overOutputWarningThreshold = ByteUtil.bytes2Uint16Le(bytes, offset);
    offset += 2;
    output.overBusCurrentTiltBackThreshold =
        ByteUtil.bytes2Uint16Le(bytes, offset);
    offset += 2;
    output.overBusCurrentWarningThreshold =
        ByteUtil.bytes2Uint16Le(bytes, offset);
    offset += 2;

    // output.phaseCurrentLimit = ByteUtil.bytes2Uint16Le(bytes, offset);
    offset += 2;
    // 保留4bytes
    offset += 4;

    output.mosTemp = ByteUtil.toInt16(ByteUtil.toInt8Int(bytes[offset]) + 80);
    offset++;
    output.motorTemp = ByteUtil.toInt16(ByteUtil.toInt8Int(bytes[offset]) + 80);
    offset++;
    output.batteryTemp =
        ByteUtil.toInt16(ByteUtil.toInt8Int(bytes[offset]) + 80);
    offset++;
    output.boardTemp = ByteUtil.toInt16(ByteUtil.toInt8Int(bytes[offset]) + 80);
    offset++;
    output.cpuTemp = ByteUtil.toInt16(ByteUtil.toInt8Int(bytes[offset]) + 80);
    offset++;
    output.imuTemp = ByteUtil.toInt16(ByteUtil.toInt8Int(bytes[offset]) + 80);
    offset++;
    output.lampTemp = ByteUtil.toInt16(ByteUtil.toInt8Int(bytes[offset]) + 80);
    offset++;
    output.brightness = ByteUtil.bytes2Uint8Le(bytes, offset);
    // 保留4bytes
  }

  @override
  int length() {
    return 74;
  }
}

/// 实时状态
class E25RealTimeState extends EucRealTimeState {
  Uint4 lowBeamState = Uint4.zero;
  Uint4 highBeamState = Uint4.zero;

  E25RealTimeState(ProductModel model, VersionWrapper version)
      : super(model, version);

  @override
  void initCompact() {
    compact = _DefaultE25RealTimeState();
  }

  @override
  String toString() {
    return 'E25RealTimeState{pcMode: $pcMode, lowBeam: $lowBeamState, highBeam: $highBeamState, dfuState: $dfuState,mcMode: $mcMode, motorState: $motorState, chargeState: $chargeState, '
        'liftedState: $liftedState, tailLightState: $tailLightState, backupBatteryState: $backupBatteryState, brakeState: $brakeState, slowDownState: $slowDownState,'
        'lowBeamState: $lowBeamState, highBeamState: $highBeamState}';
  }
}

class _DefaultE25RealTimeState extends Compact<E25RealTimeState> {
  @override
  void fromBytes(E25RealTimeState output, Uint8ClampedList bytes, int offset) {
    // 3bit
    output.pcModeValue =
        ByteUtil.toUint32(ByteUtil.bitValue(bytes[offset], 0, 3).value);
    if (output.pcModeValue.value == 0) {
      output.pcMode = Mode.idle;
    } else if (output.pcModeValue.value == 1) {
      output.pcMode = Mode.working;
    } else if (output.pcModeValue.value == 2) {
      output.pcMode = Mode.sleep;
    } else if (output.pcModeValue.value == 3) {
      output.pcMode = Mode.locked;
    }
    output.lockState = output.pcMode == Mode.locked ? Uint4(1) : Uint4.zero;
    // 3bit
    output.mcMode = ByteUtil.bitValue(bytes[offset], 3, 3);
    // 1bit
    output.motorState = ByteUtil.bitValue(bytes[offset], 6, 1);
    // 1bit
    output.chargeState = ByteUtil.bitValue(bytes[offset], 7, 1);
    offset++;
    // 1bit
    output.backupBatteryState = ByteUtil.bitValue(bytes[offset], 0, 1);
    // 1bit
    // output.chargePortDetect = ByteUtil.bitValue(bytes[offset], 1, 3);
    // output.chargePortOn = ByteUtil.bitValue(bytes[offset], 4, 1);
    // output.dcPortDetect = ByteUtil.bitValue(bytes[offset], 5, 3);
    offset++;
    // output.dcOutputEnable = ByteUtil.bitValue(bytes[offset], 0, 1);
    // 1bit
    output.headlightState = ByteUtil.bitValue(bytes[offset], 1, 1);
    // 1bit
    // output.decorativeLight = ByteUtil.bitValue(bytes[offset], 2, 1);
    // output.lifted = ByteUtil.bitValue(bytes[offset], 3, 1);
    output.tailLightState = ByteUtil.bitValue(bytes[offset], 4, 3);
    // output.fanWorkState = ByteUtil.bitValue(bytes[offset], 7, 1);
    offset++;
    output.brakeState = ByteUtil.bitValue(bytes[offset], 0, 1);
    output.slowDownState = ByteUtil.bitValue(bytes[offset], 1, 1);
    output.dfuState = ByteUtil.bitValue(bytes[offset], 2, 1);
  }

  @override
  int length() {
    return 4;
  }
}

/// 实时故障和警告
class E25RealTimeError extends EucRealTimeError {
  E25RealTimeError(ProductModel model, VersionWrapper version)
      : super(model, version);

  Uint4 motorHall1State = Uint4.zero;
  Uint4 motorHall2State = Uint4.zero;
  Uint4 batteryCommLost = Uint4.zero;
  Uint4 batteryCrossCommLost = Uint4.zero;
  Uint4 tboxComm = Uint4.zero;
  Uint4 motorStallState = Uint4.zero;
  Uint4 batteryWarningState = Uint4.zero;
  Uint4 batteryProtectState = Uint4.zero;
  Uint4 chargeOverCurrentState = Uint4.zero;
  Uint4 dcOutputOverCurrentState = Uint4.zero;
  Uint4 swCombination = Uint4.zero;
  Uint4 hwOverCurrentState = Uint4.zero;

  @override
  void initCompact() {
    compact = _DefaultE25RealTimeError();
  }

  @override
  String toString() {
    return 'E25RealTimeError{ ${super.toString()}, riskBehaviourState: $riskBehaviourState}';
  }
}

class _DefaultE25RealTimeError<E25RealTimeError>
    extends _DefaultE25RealTimeErrorImpl {}

// class DefaultE25RealTimeErrorDelegate<T extends E25RealTimeError> extends _DefaultE25RealTimeErrorImpl<T> {}

class _DefaultE25RealTimeErrorImpl<T extends E25RealTimeError>
    extends Compact<T> {
  @override
  void fromBytes(T output, Uint8ClampedList bytes, int offset) {
    output.originalValue = ByteUtil.bytes2Int32Le(bytes, offset);

    output.iPhaseSensorState = ByteUtil.bitValue(bytes[offset], 0, 1);
    output.iBusSensorState = ByteUtil.bitValue(bytes[offset], 1, 1);
    output.motorHall1State = ByteUtil.bitValue(bytes[offset], 2, 1);
    output.motorHall2State = ByteUtil.bitValue(bytes[offset], 3, 1);
    output.batteryState = ByteUtil.bitValue(bytes[offset], 4, 1);
    output.imuSensorState = ByteUtil.bitValue(bytes[offset], 5, 1);
    output.controllerCom1State = ByteUtil.bitValue(bytes[offset], 6, 1);
    output.controllerCom2State = ByteUtil.bitValue(bytes[offset], 7, 1);
    offset++;
    output.bleCom1State = ByteUtil.bitValue(bytes[offset], 0, 1);
    output.bleCom2State = ByteUtil.bitValue(bytes[offset], 1, 1);
    output.batteryCommLost = ByteUtil.bitValue(bytes[offset], 2, 1);
    output.batteryCrossCommLost = ByteUtil.bitValue(bytes[offset], 3, 1);
    output.mosTempSensorState = ByteUtil.bitValue(bytes[offset], 4, 1);
    output.motorTempSensorState = ByteUtil.bitValue(bytes[offset], 5, 1);
    output.boardTempSensorState = ByteUtil.bitValue(bytes[offset], 6, 1);
    output.fanState = ByteUtil.bitValue(bytes[offset], 7, 1);
    offset++;
    output.rtcState = ByteUtil.bitValue(bytes[offset], 0, 1);
    output.externalRomState = ByteUtil.bitValue(bytes[offset], 1, 1);
    output.vBusSensorState = ByteUtil.bitValue(bytes[offset], 2, 1);
    output.vBatterySensorState = ByteUtil.bitValue(bytes[offset], 3, 1);
    output.canNotPowerOffState = ByteUtil.bitValue(bytes[offset], 4, 1);
    output.canNotChargeState = ByteUtil.bitValue(bytes[offset], 5, 1);
    output.tboxComm = ByteUtil.bitValue(bytes[offset], 6, 1);
    // 剩余1byte保留
    offset++;

    offset++;

    // 警告
    output.underVoltageState = ByteUtil.bitValue(bytes[offset], 0, 1);
    output.overVoltageState = ByteUtil.bitValue(bytes[offset], 1, 1);
    output.overBusCurrentState = ByteUtil.bitValue(bytes[offset], 2, 2);
    output.lowBatteryState = ByteUtil.bitValue(bytes[offset], 4, 2);
    output.overMosTempState = ByteUtil.bitValue(bytes[offset], 6, 1);
    output.overMotorTempState = ByteUtil.bitValue(bytes[offset], 7, 1);
    offset++;
    output.overBoardTempState = ByteUtil.bitValue(bytes[offset], 0, 1);
    output.cpuOverTempState = ByteUtil.bitValue(bytes[offset], 1, 1);
    output.imuOverTempState = ByteUtil.bitValue(bytes[offset], 2, 1);
    output.overSpeedState = ByteUtil.bitValue(bytes[offset], 3, 1);
    output.outputSaturationState = ByteUtil.bitValue(bytes[offset], 4, 1);
    output.motorSpinState = ByteUtil.bitValue(bytes[offset], 5, 1);
    output.motorStallState = ByteUtil.bitValue(bytes[offset], 6, 1);
    output.postureState = ByteUtil.bitValue(bytes[offset], 7, 1);
    offset++;
    output.riskBehaviourState = ByteUtil.bitValue(bytes[offset], 0, 1);
    output.motorNoLoadState = ByteUtil.bitValue(bytes[offset], 1, 1);
    output.noSelfTestState = ByteUtil.bitValue(bytes[offset], 2, 1);
    output.powerKeyLongPressState = ByteUtil.bitValue(bytes[offset], 3, 1);
    output.someBatteriesNotWorkState = ByteUtil.bitValue(bytes[offset], 4, 1);
    output.batteryNotCaliState = ByteUtil.bitValue(bytes[offset], 5, 1);
    output.batteryWarningState = ByteUtil.bitValue(bytes[offset], 6, 1);
    output.batteryProtectState = ByteUtil.bitValue(bytes[offset], 7, 1);
    offset++;
    output.chargeOverCurrentState = ByteUtil.bitValue(bytes[offset], 0, 1);
    output.dcOutputOverCurrentState = ByteUtil.bitValue(bytes[offset], 1, 1);
    output.swCombination = ByteUtil.bitValue(bytes[offset], 2, 1);
    output.forceDfuState = ByteUtil.bitValue(bytes[offset], 3, 1);
    output.deviceLockState = ByteUtil.bitValue(bytes[offset], 4, 1);
    output.hwCompatibilityState = ByteUtil.bitValue(bytes[offset], 5, 1);
    output.fanLowSpeedState = ByteUtil.bitValue(bytes[offset], 6, 2);
    output.hwOverCurrentState = ByteUtil.bitValue(bytes[offset], 7, 1);
  }

  @override
  int length() {
    return 8;
  }
}

class E25BatteryRealTimeInfo extends AbsBatteryRealTimeInfo {
  E25SingleBatteryRealTimeInfo? _battery1;
  E25SingleBatteryRealTimeInfo? _battery2;

  E25BatteryRealTimeInfo(ProductModel model, VersionWrapper version)
      : super(model, version);

  @override
  void initCompact() {
    compact = _DefaultE25BatteryRealTimeInfo(model, version);
  }

  get battery1 {
    if (_battery1 == null)
      throw ProtocolParseException(
          "Unexpected exception. Please call [fromBytes] to gen battery info first!");
    return _battery1!;
  }

  get battery2 {
    if (_battery2 == null)
      throw ProtocolParseException(
          "Unexpected exception. Please call [fromBytes] to gen battery info first!");
    return _battery2!;
  }

  @override
  String toString() {
    return 'E25BatteryRealTimeInfo{_battery1: $_battery1, _battery2: $_battery2}';
  }
}

class _DefaultE25BatteryRealTimeInfo extends Compact<E25BatteryRealTimeInfo> {
  final ProductModel _model;
  final VersionWrapper _versionWrapper;

  _DefaultE25BatteryRealTimeInfo(this._model, this._versionWrapper);

  @override
  void fromBytes(
      E25BatteryRealTimeInfo output, Uint8ClampedList bytes, int offset) {
    output._battery1 = E25SingleBatteryRealTimeInfo(_model, _versionWrapper);
    output._battery1!.fromBytes(bytes, offset);
    offset += output._battery1!.length();
    output._battery2 = E25SingleBatteryRealTimeInfo(_model, _versionWrapper);
    output._battery2!.fromBytes(bytes, offset);
  }

  @override
  int length() {
    return 16;
  }
}

class E25SingleBatteryRealTimeInfo extends AbsBatteryRealTimeInfo {
  Uint16 voltage = Uint16.zero;
  Int16 chargeCurrent = Int16.zero;
  Int16 dischargeCurrent = Int16.zero;

  Uint4 detected = Uint4.zero;
  Uint4 enable = Uint4.zero;
  Uint4 charge = Uint4.zero;

  Uint4 errorLogic = Uint4.zero;
  Uint4 errorSignal = Uint4.zero;
  Uint4 errorVoltageSensor = Uint4.zero;
  Uint4 errorCurrentSensor = Uint4.zero;
  Uint4 errorCannotCharge = Uint4.zero;
  Uint4 batteryWarning = Uint4.zero;
  Uint4 batteryProtect = Uint4.zero;
  Uint4 batteryError = Uint4.zero;

  E25SingleBatteryRealTimeInfo(ProductModel model, VersionWrapper version)
      : super(model, version);

  @override
  void initCompact() {
    compact = _DefaultE25SingleBatteryRealTimeInfo();
  }

  @override
  String toString() {
    return 'E25SingleBatteryRealTimeInfo{voltage: $voltage, chargeCurrent: $chargeCurrent, dischargeCurrent: $dischargeCurrent, detected: $detected, enable: $enable, charge: $charge, errorLogic: $errorLogic, errorSignal: $errorSignal, errorVoltageSensor: $errorVoltageSensor, errorCurrentSensor: $errorCurrentSensor, errorCannotCharge: $errorCannotCharge, batteryWarning: $batteryWarning, batteryProtect: $batteryProtect, batteryError: $batteryError}';
  }
}

class _DefaultE25SingleBatteryRealTimeInfo
    extends Compact<E25SingleBatteryRealTimeInfo> {
  @override
  void fromBytes(
      E25SingleBatteryRealTimeInfo output, Uint8ClampedList bytes, int offset) {
    output.voltage = ByteUtil.bytes2Uint16Le(bytes, offset);
    offset += 2;
    output.chargeCurrent = ByteUtil.bytes2Int16Le(bytes, offset);
    offset += 2;
    output.dischargeCurrent = ByteUtil.bytes2Int16Le(bytes, offset);
    offset += 2;

    output.detected = ByteUtil.bitValue(bytes[offset], 0, 1);
    output.enable = ByteUtil.bitValue(bytes[offset], 1, 1);
    output.charge = ByteUtil.bitValue(bytes[offset], 2, 1);
    // 剩余3bit保留
    output.errorLogic = ByteUtil.bitValue(bytes[offset], 6, 1);
    output.errorSignal = ByteUtil.bitValue(bytes[offset], 7, 1);

    offset++;

    output.errorVoltageSensor = ByteUtil.bitValue(bytes[offset], 0, 1);
    output.errorCurrentSensor = ByteUtil.bitValue(bytes[offset], 1, 1);
    output.errorCannotCharge = ByteUtil.bitValue(bytes[offset], 2, 1);
    output.batteryWarning = ByteUtil.bitValue(bytes[offset], 3, 1);
    output.batteryProtect = ByteUtil.bitValue(bytes[offset], 4, 1);
    output.batteryError = ByteUtil.bitValue(bytes[offset], 5, 1);
    // 剩余2bit保留
  }

  @override
  int length() {
    return 8;
  }
}
